﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Diagnostics;

namespace Xceed.Silverlight.Data
{
  [DebuggerDisplay( "Value = {Value}, IsEstimate = {IsEstimate}" )]
  internal sealed class EstimateInt64 : IEquatable<EstimateInt64>, IEquatable<long>
  {
    #region Constructors

    internal EstimateInt64( long value )
      : this( value, false )
    {
    }

    internal EstimateInt64( long value, bool isEstimate )
    {
      this.Value = value;
      this.IsEstimate = isEstimate;
    }

    #endregion

    #region Value Property

    internal long Value
    {
      get;
      private set;
    }

    #endregion

    #region IsEstimate Property

    internal bool IsEstimate
    {
      get;
      private set;
    }

    #endregion

#if DEBUG
    public override string ToString()
    {
      return string.Format( "(Val={0}, Est={1})", this.Value, this.IsEstimate );
    }
#endif  //DEBUG

    public static implicit operator EstimateInt64( long value )
    {
      return new EstimateInt64( value, false );
    }

    public static bool operator ==( EstimateInt64 x, EstimateInt64 y )
    {
      if( object.ReferenceEquals( x, null ) )
        return object.ReferenceEquals( y, null );

      return x.Equals( y );
    }

    public static bool operator ==( EstimateInt64 x, long scalar )
    {
      return ( !object.ReferenceEquals( x, null ) )
          && ( x.Equals( scalar ) );
    }

    public static bool operator !=( EstimateInt64 x, EstimateInt64 y )
    {
      return !( x == y );
    }

    public static bool operator !=( EstimateInt64 x, long scalar )
    {
      return !( x == scalar );
    }

    public override int GetHashCode()
    {
      return this.Value.GetHashCode();
    }

    public override bool Equals( object obj )
    {
      return this.Equals( obj as EstimateInt64 );
    }

    public bool Equals( long scalar )
    {
      return EstimateInt64.Equals( this, scalar, false );
    }

    public bool Equals( EstimateInt64 obj )
    {
      return EstimateInt64.Equals( obj, this.Value, this.IsEstimate );
    }

    public static EstimateInt64 operator +( EstimateInt64 first, EstimateInt64 second )
    {
      EstimateInt64.CheckForNull( first, "first" );
      EstimateInt64.CheckForNull( second, "second" );

      return ( EstimateInt64.IsAdditiveIdentity( second ) )
               ? first
               : new EstimateInt64(
                       first.Value + second.Value,
                       EstimateInt64.IsBecomingEstimate( first, second ) );
    }

    public static EstimateInt64 operator +( EstimateInt64 value, long scalar )
    {
      EstimateInt64.CheckForNull( value, "value" );

      return ( EstimateInt64.IsAdditiveIdentity( scalar ) )
               ? value
               : new EstimateInt64( value.Value + scalar, value.IsEstimate );
    }

    public static EstimateInt64 operator -( EstimateInt64 first, EstimateInt64 second )
    {
      EstimateInt64.CheckForNull( first, "first" );
      EstimateInt64.CheckForNull( second, "second" );

      return ( EstimateInt64.IsAdditiveIdentity( second ) )
               ? first
               : new EstimateInt64(
                       first.Value - second.Value,
                       EstimateInt64.IsBecomingEstimate( first, second ) );
    }

    public static EstimateInt64 operator -( EstimateInt64 value, long scalar )
    {
      EstimateInt64.CheckForNull( value, "value" );

      return ( EstimateInt64.IsAdditiveIdentity( scalar ) )
               ? value
               : new EstimateInt64( value.Value - scalar, value.IsEstimate );
    }

    public static EstimateInt64 operator -( EstimateInt64 self )
    {
      EstimateInt64.CheckForNull( self, "self" );

      return ( EstimateInt64.IsAdditiveIdentity( self ) )
               ? self
               : new EstimateInt64( -self.Value, self.IsEstimate );
    }

    public static EstimateInt64 operator *( EstimateInt64 value, long scalar )
    {
      EstimateInt64.CheckForNull( value, "value" );

      return ( EstimateInt64.IsMultiplicativeIdentity( scalar ) )
               ? value
               : new EstimateInt64( value.Value * scalar, value.IsEstimate );
    }

    private static void CheckForNull( EstimateInt64 value, string parameterName )
    {
      if( value == null )
        throw new ArgumentNullException( parameterName );
    }

    private static bool IsBecomingEstimate( EstimateInt64 first, EstimateInt64 second )
    {
      return ( first.IsEstimate || second.IsEstimate );
    }

    private static bool IsAdditiveIdentity( EstimateInt64 value )
    {
      return ( EstimateInt64.IsAdditiveIdentity( value.Value ) && !value.IsEstimate );
    }

    private static bool IsAdditiveIdentity( long scalar )
    {
      return ( scalar == 0 );
    }

    private static bool IsMultiplicativeIdentity( EstimateInt64 value )
    {
      return ( EstimateInt64.IsMultiplicativeIdentity( value.Value ) && !value.IsEstimate );
    }

    private static bool IsMultiplicativeIdentity( long scalar )
    {
      return ( scalar == 1 );
    }

    private static bool Equals( EstimateInt64 obj, long value, bool isEstimate )
    {
      return ( !object.ReferenceEquals( obj, null ) )
          && ( obj.Value == value )
          && ( obj.IsEstimate == isEstimate );
    }
  }
}
